package com.jushu.storbox.actions;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;

import android.content.Context;
import android.os.Handler;
import android.widget.Toast;

import com.jushu.storbox.R;
import com.jushu.storbox.ShareDriveApplication;
import com.jushu.storbox.callback.ICallback;
import com.jushu.storbox.constant.Constant;
import com.jushu.storbox.constant.UiConstant;
import com.jushu.storbox.database.DAOFactory;
import com.jushu.storbox.database.IFolderDao;
import com.jushu.storbox.entities.FileFolderInfo;
import com.jushu.storbox.entities.FileInfo;
import com.jushu.storbox.entities.FileType;
import com.jushu.storbox.entities.FolderInfo;
import com.jushu.storbox.handler.ClientExceptionRelateHandler;
import com.jushu.storbox.manager.DownloadTaskManager;
import com.jushu.storbox.service.ILocalFileService;
import com.jushu.storbox.service.IlocalFolderService;
import com.jushu.storbox.service.ServiceFactory;
import com.jushu.storbox.task.tqueue.DownloadTask;
import com.jushu.storbox.util.CollectionUtils;
import com.jushu.storbox.util.DirectoryUtil;
import com.huawei.sharedrive.sdk.android.exception.ClientException;
import com.huawei.sharedrive.sdk.android.modelV2.request.FolderListRequestV2;
import com.huawei.sharedrive.sdk.android.modelV2.request.Order;
import com.huawei.sharedrive.sdk.android.modelV2.response.FileInfoResponseV2;
import com.huawei.sharedrive.sdk.android.modelV2.response.FolderListResponseV2;
import com.huawei.sharedrive.sdk.android.modelV2.response.FolderResponse;
import com.huawei.sharedrive.sdk.android.serviceV2.FolderClientV2;

public class DownloadEntity {

	private Context context;
	private Handler msgHandler;
	private FileFolderInfo folderInfo;
	private boolean syncStatus = false;
	private ILocalFileService localFileDbService;
	private IlocalFolderService localFolderDbService;
	
//	private int progress;
//	private long downloadedSize=0;
//	private long totalSize=1;
	
	private int tempSynStatus = Constant.DOWNLOAD_STATUS_NOCACHE_DB;

	public DownloadEntity(Context context, Handler msgHandler, FileFolderInfo folderInfo, boolean syncStatus) {
		this.context = context;
		this.msgHandler = msgHandler;
		this.syncStatus = syncStatus;
		this.folderInfo = folderInfo;
		this.localFileDbService = ServiceFactory.instance(context).getLocalFileService();
		this.localFolderDbService = ServiceFactory.instance(context).getLocalFolderService();
		
		folderInfo.setSync(syncStatus);
		folderInfo.notifyChange();
		
		if(syncStatus) {
			tempSynStatus = Constant.DOWNLOAD_STATUS_CACHE_DB;
		} else {
			tempSynStatus = Constant.DOWNLOAD_STATUS_NOCACHE_DB;
		}
		DAOFactory.instance(context).getFileDao().updateSyncStatus(folderInfo.getOwnerId(), folderInfo.getId(), tempSynStatus);
	}

	public void startDownloadFile() throws ClientException {
		boolean needToUpdata = false;
		//if them is not same, then download file from server
		if(needToUpdata || folderInfo.getTransStatus() != Constant.DOWNLOAD_SUCCESS_UPDATE_DB) {
			DownloadTaskManager.addTask(new DownloadTask(context, callback, folderInfo, syncStatus));
		}
	}
	
	public void startDownloadFolder() throws ClientException {
		FolderResponse response = ServiceFactory.getRemoteFolderService().getFolderResponse(folderInfo.getOwnerId(), folderInfo.getId());
		if(response != null) {
			new Thread(new VirtureProgress(context, folderInfo)).start();
			doDownloadFolder(response);
		} else {
			//download folder is not exists
		}
	}
	
	private void doDownloadFolder(FolderResponse folder) throws ClientException {
		handleFolderSelf(folder);
		FolderListResponseV2 response;
		response = requestFolderInfomation(folder.getId(), folder.getOwnerBy());
		
		handleSubFileCollection(folder, response);
		handleSubFolderCollection(folder, response);
	}
	
	private FolderListResponseV2 requestFolderInfomation(String id, String ownerId) throws ClientException {
		List<Order> olist = new ArrayList<Order>();
		olist.add(new Order("modifiedAt", "DESC"));
		
		FolderListRequestV2 request = new FolderListRequestV2();
		request.setFolderID(id);
		request.setLimit(1000);
		request.setOffset(0);
		request.setOwnerID(ownerId);
		request.setOrder(olist);
		
		return FolderClientV2.getInstance()
			.getFolderInfoList(request, ShareDriveApplication.getInstance().getAuthorization());
		
	}
	
	private void handleFolderSelf(FolderResponse folder) {
		localFolderDbService.updateSyncStatus(tempSynStatus, folder.getOwnerBy(), folder.getId());
		DAOFactory.instance(context).getFileDao().updateSyncStatus(folder.getOwnerBy(), folder.getId(), tempSynStatus);
	}
	
	private void handleSubFolderCollection(FolderResponse folder, FolderListResponseV2 response) throws ClientException {
		localFolderDbService.updateSyncStatus(tempSynStatus, folder.getOwnerBy(), folder.getId());
		HashMap<String, FolderInfo> folderDatas = localFolderDbService.getMappedFolderDatas(folder.getOwnerBy(), folder.getId());
		compareServiceClientFolderAndDownload(context, response.getFolders(), folderDatas);
	
		List<FolderResponse> folderResponseList = response.getFolders();
		if (null != folderResponseList) {
			for (FolderResponse folderResponse : folderResponseList) {
				doDownloadFolder(folderResponse);
			}
		}
	}
	
	private void handleSubFileCollection(FolderResponse parent, FolderListResponseV2 response) throws ClientException {
		HashMap<String, FileInfo> mapDatas = localFileDbService.getMappedFileList(parent.getOwnerBy(), parent.getId());
		compareServiceClientFileAndDownload(context, response.getFiles(), mapDatas, parent.getId());
	}
	
	public void compareServiceClientFolderAndDownload(Context context,
	        List<FolderResponse> serverList, HashMap<String, FolderInfo> clientList) {
	        if (CollectionUtils.isEmpty(serverList) && CollectionUtils.isEmpty(clientList)) {
	            return;
	        }
	        if (CollectionUtils.isEmpty(serverList)) {
	        	Set<Entry<String, FolderInfo>> datas = clientList.entrySet();
	            for (Entry<String, FolderInfo> localFolder : datas) {
	            	localFolderDbService.deleteFolderAndChildVirtual(localFolder.getValue());
	            }
	            return;
	        }
	        for (FolderResponse frServer : serverList) {	                	
	            FolderInfo localFolder = clientList.get(frServer.getId());
	            if(localFolder != null) {
	                if (frServer.getModifiedAt() != localFolder.getModifiedAt()) {
	                	DAOFactory.instance(context).getFolderDao().updateFolder(frServer);
	                }
	                localFolderDbService.updateSyncStatus(tempSynStatus, frServer.getOwnerBy(), frServer.getId());
                	localFolderDbService.updateTransStatus(Constant.DOWNLOAD_SUCCESS_UPDATE_DB, frServer.getOwnerBy(), frServer.getId());
	            } else {
	            	FolderInfo fileInfo = DAOFactory.instance(context).getFolderDao().getFolderById(frServer.getOwnerBy(), frServer.getId());
	                if (null != fileInfo) { ////move from other space
	                	DAOFactory.instance(context).getFolderDao().updateFolder(frServer);
	                	//set the new item's syncFlag to sync
	                	DAOFactory.instance(context).getFileDao().updateSyncStatus(frServer.getOwnerBy(), frServer.getId(), tempSynStatus);
	                } else {//real add new item
	                    DAOFactory.instance(context).getFolderDao().insertFolder(frServer, tempSynStatus);
	                }
	                localFolderDbService.updateTransStatus(Constant.DOWNLOAD_SUCCESS_UPDATE_DB, frServer.getOwnerBy(), frServer.getId());
	            }
	            
	            clientList.remove(frServer.getId());
	        }
	        
	        //process those local exists and server not exists, maybe server move to other space
	        Set<Entry<String, FolderInfo>> datas = clientList.entrySet();
	        for (Entry<String, FolderInfo> localFolder : datas) {
	        	localFolderDbService.deleteFolderAndChildVirtual(localFolder.getValue());
	        }
	    }
	
	public void compareServiceClientFileAndDownload(Context context,
            List<FileInfoResponseV2> serverList, HashMap<String, FileInfo> clientDatas, String folderID) {
            if (CollectionUtils.isEmpty(serverList) && CollectionUtils.isEmpty(clientDatas)) {
                return;
            }
            if (CollectionUtils.isEmpty(serverList)) {
            	Set<Entry<String, FileInfo>> datas = clientDatas.entrySet();
                for (Entry<String, FileInfo> localFolder : datas) {
                	localFileDbService.deleteFileVirtual(localFolder.getValue());
                }
                return;
            }
            for (FileInfoResponseV2 frServer : serverList) {
            	boolean shouldUpdateFileContent = false;
                FileInfo localFile = clientDatas.get(frServer.getId());
                if(localFile != null) {//the node save in current folder
	                if (frServer.getModifiedAt() != localFile.getModifiedAt()) {
	                    DAOFactory.instance(context).getFileDao().updateFile(frServer, false, true);
	                    if(!frServer.getIdentity().equals(localFile.getIdentity())) {
	                    	shouldUpdateFileContent = true;
	                    }
	                }
                } else {
                	FileInfo fileInfo = (FileInfo) DAOFactory.instance(context).getFileDao().getFile(frServer.getOwnerBy(),  frServer.getId());
                    if (null != fileInfo) {//move from other space
                    	DAOFactory.instance(context).getFileDao().updateFile(frServer, false, false);
                    	if(!frServer.getIdentity().equals(fileInfo.getIdentity())) {//content is changed
                        	shouldUpdateFileContent = true;
                    	}
                    } else {//real add new element on server
                        DAOFactory.instance(context).getFileDao().insertFile(frServer);
                    	shouldUpdateFileContent = true;
                    }
                    //set the new item's syncFlag to sync
                    DAOFactory.instance(context).getFileDao().updateSyncStatus(frServer, tempSynStatus);
                }
                
                FileInfo fileInfo = DAOFactory.instance(context).getFileDao().getFile(frServer);
                if (shouldUpdateFileContent || fileInfo.getTransStatus() != Constant.DOWNLOAD_SUCCESS_UPDATE_DB ) {
                	String path = DirectoryUtil.generateFileDownloadPath(context, frServer.getOwnerBy(), frServer.getId(), frServer.getName());
                    fileInfo.valueOf(frServer);
                    DAOFactory.instance(context).getFileDao().updateSyncStatus(frServer, tempSynStatus);
                    DAOFactory.instance(context).getFileDao().updateLocalPath(frServer, path);
                    DownloadTaskManager.addTask(new DownloadTask(context, callback, fileInfo, true));
                } else if(!fileInfo.isSync()) {// only not change the sync flag
            		DAOFactory.instance(context).getFileDao().updateSyncStatus(frServer,tempSynStatus);
                }
                
                //remove node witch proceess finished
                clientDatas.remove(frServer.getId());
            }
            
            //delete those server deleted
            Set<Entry<String, FileInfo>> datas = clientDatas.entrySet();
            for (Entry<String, FileInfo> localFile : datas) {
            	localFileDbService.deleteFileVirtual(localFile.getValue());
            }
            
        }
	
//	private void addDownloadedSize(long downloadSize) {
//		downloadedSize += downloadSize;
//		progress = (int) (downloadedSize / totalSize);
//	}
	
	ICallback callback = new ICallback() {
		public void onStart() {
			if(msgHandler != null) {
//				Message msg = msgHandler.obtainMessage();
//				msg.sendToTarget();
			}
		}
		public void onFailure(Throwable t, int statusCode) {
			int transState = Constant.DOWNLOAD_FAIL_UPDATE_DB;
			if(statusCode == ClientExceptionRelateHandler.ERROR_CODE_403_NO_RIGHT || statusCode == Constant.DOWNLOAD_FAIL_FILE_LARGERTHAN_CACHESIZE){
				transState = Constant.DOWNLOAD_NON_UPDATE_DB;
				if(folderInfo.getIsFile() == FileType.FILE_TYPE_VALUE){
					DAOFactory.instance(context).getFileDao().updateSyncStatus(folderInfo.getOwnerId(), folderInfo.getId(), Constant.DOWNLOAD_STATUS_NOCACHE_DB);
				}else{
					DAOFactory.instance(context).getFolderDao().updateSyncStatuc(folderInfo.getOwnerId(), folderInfo.getId(), Constant.DOWNLOAD_STATUS_NOCACHE_DB);
				}
				
				int tmpTtransStatus = transState;
				if(statusCode == Constant.DOWNLOAD_FAIL_FILE_LARGERTHAN_CACHESIZE){
					tmpTtransStatus = Constant.DOWNLOAD_RES_NOSPACE;
				}else{
					tmpTtransStatus = Constant.DOWNLOAD_RES_NOEXIST_NORIGHT;
				}
				folderInfo.setTransStatus(tmpTtransStatus);
			}else{
				if(statusCode == UiConstant.TASK_TRANSLATE_CANCELED){
					folderInfo.setTransStatus(Constant.DOWNLOAD_NON_UPDATE_DB);
				}else{
					folderInfo.setTransStatus(transState);
				}
			}
			
			if(folderInfo.getIsFile() == FileType.FILE_TYPE_VALUE){
				DAOFactory.instance(context).getFileDao()
	 			.updateTransStatus(folderInfo.getOwnerId(), folderInfo.getId(), 
	 					transState);
			}else{
				DAOFactory.instance(context).getFolderDao()
	 			.updateTransStatus(folderInfo.getOwnerId(), folderInfo.getId(), 
	 					transState);
			}
			folderInfo.notifyChange();
		}
		public void onSuccess() {
//			if(msgHandler != null) {
////				Message msg = msgHandler.obtainMessage();
////				msg.sendToTarget();
//			}
		}
		public void onProgress(int currentProgress, long currentSize, long maxSize) {
//			addDownloadedSize(maxSize);
//			folderInfo.setProgress(progress);
//			ControlInfo cotrol = folderInfo.getControlInfo();
//			if(cotrol != null) {
//				cotrol.notifyChange();
//			}
		}
		@Override
		public void onStop() {
		}
		@Override
		public void onCanceled() {
		}
		@Override
		public void onDettach() {
		}
	};
}